﻿using SvnAPI.Base.Enumerator;
using SvnAPI.Base.Extension;
using SvnAPI.Command.Base;
using SvnAPI.Command.Interface;
using System;
using System.ComponentModel.DataAnnotations;

namespace SvnAPI.Command.Command
{
    /// <summary>
    /// Class to execute the specific command on svn look tool and execute base command to get the result.
    /// </summary>
    public sealed class SvnLookCommand : BaseCommand
    {
        #region Variables

        /// <summary>
        /// Type of the application to execute the command.
        /// </summary>
        private String COMMAND_TOOL_TYPE = CommandToolType.svn_look.GetDescription<DisplayAttribute>();

        #endregion

        #region Properties

        /// <summary>
        /// Repository path to get the result.
        /// </summary>
        public String RepositoryPath { get; set; }

        /// <summary>
        /// Path in verify the result of command.
        /// </summary>
        public String PathInRepository { get; set; }

        /// <summary>
        /// Transaction or Revision number.
        /// </summary>
        public String TxnRevision { get; set; }

        #endregion

        #region Constructors
        
        /// <summary>
        /// Constructor for the class.
        /// </summary>
        /// <param name="txnRevision">Transaction number.</param>
        /// <param name="repositoryPath">Repository path.</param>
        /// <param name="pathInRepository">Optional parameter, path in to Verify.</param>
        public SvnLookCommand(String txnRevision, String repositoryPath, String pathInRepository = "")
        {
            this.FileName = String.Format(@"{0}bin\{1}", SVN_SERVER, COMMAND_TOOL_TYPE);

            this.TxnRevision = txnRevision;
            this.RepositoryPath = repositoryPath;
            this.PathInRepository = pathInRepository;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Get the author of a revision or transaction in the repository.
        /// </summary>
        /// <param name="executionType">Type of execution.</param>
        /// <returns>Return result of execution.</returns>
        public IResult Author(ExecutionType executionType)
        {
            try
            {
                String operationType = SvnLookCommandType.author.GetDescription<DisplayAttribute>();

                if (executionType == ExecutionType.non_used)
                {
                    Arguments = String.Format("{0} {1}", operationType, RepositoryPath);
                }
                else
                {
                    String execType = executionType.GetDescription<DisplayAttribute>();

                    Arguments = String.Format("{0} {1} {2} {3}", operationType, execType, TxnRevision, RepositoryPath);
                }

                return base.Run();
            }
            catch (Exception)
            {                
                throw;
            }
        }

        /// <summary>
        /// Get the contents of a file.
        /// </summary>
        /// <param name="executionType">Type of execution.</param>
        /// <returns>Return result of execution.</returns>
        public IResult Cat(ExecutionType executionType)
        {
            try
            {
                String operationType = SvnLookCommandType.cat.GetDescription<DisplayAttribute>();

                if (executionType == ExecutionType.non_used)
                {
                    Arguments = String.Format("{0} \"{1}\" \"{2}\"", operationType, RepositoryPath, PathInRepository);
                }
                else
                {
                    String execType = executionType.GetDescription<DisplayAttribute>();

                    Arguments = String.Format("{0} {1} {2} {3} {4}", operationType, execType, TxnRevision, RepositoryPath, PathInRepository);
                }

                return base.Run();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Get the paths that were changed in a particular revision or transaction, as well as “svn update-style” status letters in the first two columns:
        /// 
        /// 'A ' Item added to repository
        /// 'D ' Item deleted from repository
        /// 'U ' File contents changed
        /// '_U' Properties of item changed; note the leading underscore
        /// 'UU' File contents and properties changed
        /// 
        /// Files and directories can be distinguished, as directory paths are displayed with a trailing “/” character.
        /// 
        /// </summary>
        /// <param name="executionType">Type of execution.</param>
        /// <param name="isCopyInfo">optional value, true to show detailed copy source information.</param>
        /// <returns>Return the paths that were changed in a particular revision or transaction.</returns>
        /// <returns>Return result of execution.</returns>
        public IResult Changed(ExecutionType executionType, Boolean isCopyInfo = false)
        {
            try
            {
                String operationType = SvnLookCommandType.changed.GetDescription<DisplayAttribute>();
                String copy_info = SvnLookOptions.copy_info.GetOptionDescription<DisplayAttribute>(isCopyInfo);

                if (executionType == ExecutionType.non_used)
                {
                    Arguments = String.Format("{0} {1} \"{2}\"", operationType, copy_info, RepositoryPath);
                }
                else
                {
                    String execType = executionType.GetDescription<DisplayAttribute>();

                    Arguments = String.Format("{0} {1} {2} \"{3}\" \"{4}\"", operationType, execType, copy_info, TxnRevision, RepositoryPath);
                }

                return base.Run();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Get the datestamp of a revision or transaction in a repository.
        /// </summary>
        /// <param name="executionType">Type of execution.</param>
        /// <returns>Return result of execution.</returns>
        public IResult Date(ExecutionType executionType)
        {
            try
            {
                String operationType = SvnLookCommandType.date.GetDescription<DisplayAttribute>();
                
                if (executionType == ExecutionType.non_used)
                {
                    Arguments = String.Format("{0} \"{1}\"", operationType, RepositoryPath);
                }
                else
                {
                    String execType = executionType.GetDescription<DisplayAttribute>();

                    Arguments = String.Format("{0} {1} \"{2}\" \"{3}\"", operationType, execType, TxnRevision, RepositoryPath);
                }                    

                return base.Run();
            }
            catch (Exception)
            {
                throw;
            }
        }
        
        /// <summary>
        /// Get GNU-style differences of changed files and properties in a repository.
        /// </summary>
        /// <param name="executionType">Type of execution.</param>
        /// <param name="isDiffCopyFrom">optional value, true to show differences for copied items against the copy source.</param>
        /// <param name="idNoDiffAdded">optional value, true to show differences for added files.</param>
        /// <param name="idNoDiffDeleted">optional value, true to show differences for deleted files.</param>
        /// <param name="isExtension">optional value, true to show extensions.</param>
        /// <param name="listExtensions">optional value, List of extensions.</param>
        /// <returns>Return result of execution.</returns>
        public IResult Diff(ExecutionType executionType, Boolean isDiffCopyFrom = false, Boolean idNoDiffAdded = false, Boolean idNoDiffDeleted = false, Boolean isExtension = false, String[] listExtensions = null)
        {
            try
            {
                String operationType = SvnLookCommandType.diff.GetDescription<DisplayAttribute>();

                if (executionType == ExecutionType.non_used)
                {
                    Arguments = String.Format("{0} \"{1}\"", operationType, RepositoryPath);
                }
                else
                {
                    String execType = executionType.GetDescription<DisplayAttribute>();
                    String diff_copy_from = SvnLookOptions.diff_copy_from.GetOptionDescription<DisplayAttribute>(isDiffCopyFrom);
                    String no_diff_added = SvnLookOptions.no_diff_added.GetOptionDescription<DisplayAttribute>(idNoDiffAdded);
                    String no_diff_deleted = SvnLookOptions.no_diff_deleted.GetOptionDescription<DisplayAttribute>(idNoDiffDeleted);
                    String extensions = SvnLookOptions.extensions.GetOptionDescription<DisplayAttribute>(isExtension);

                    if (isExtension)
                    {   
                        String exts = String.Join("", listExtensions);

                        Arguments = String.Format("{0} {1} {2} {3} {4} {5} {6} \"{7}\" \"{8}\"", operationType, execType, diff_copy_from, no_diff_added, no_diff_deleted, extensions, exts, TxnRevision, RepositoryPath);
                    }
                    else
                    {
                        Arguments = String.Format("{0} {1} {2} {3} {4} \"{5}\" \"{6}\"", operationType, execType, diff_copy_from, no_diff_added, no_diff_deleted, TxnRevision, RepositoryPath);
                    }
                }

                return base.Run();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Get the directories that were themselves changed (property edits) or whose file children were changed.
        /// </summary>
        /// <param name="executionType">Type of execution.</param>
        /// <returns>Return result of execution.</returns>
        public IResult DirsChanged(ExecutionType executionType)
        {
            try
            {
                String operationType = SvnLookCommandType.dirs_changed.GetDescription<DisplayAttribute>();

                if (executionType == ExecutionType.non_used)
                {
                    Arguments = String.Format("{0} \"{1}\"", operationType, RepositoryPath);
                }
                else
                {
                    String execType = executionType.GetDescription<DisplayAttribute>();

                    Arguments = String.Format("{0} {1} \"{2}\" \"{3}\"", operationType, execType, TxnRevision, RepositoryPath);
                }

                return base.Run();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Get the file size (in bytes) of the file located at Repository in the HEAD revision of the repository followed by an end-of-line character.
        /// </summary>
        /// <param name="executionType">Type of execution.</param>
        /// <returns>Return result of execution.</returns>
        public IResult FileSize(ExecutionType executionType)
        {
            try
            {
                String operationType = SvnLookCommandType.file_size.GetDescription<DisplayAttribute>();

                if (executionType == ExecutionType.non_used)
                {
                    Arguments = String.Format("{0} \"{1}\" \"{2}\"", operationType, RepositoryPath, PathInRepository);
                }
                else
                {
                    String execType = executionType.GetDescription<DisplayAttribute>();

                    Arguments = String.Format("{0} {1} \"{2}\" \"{3}\" \"{4}\"", operationType, execType, TxnRevision, RepositoryPath, PathInRepository);
                }

                return base.Run();
            }
            catch (Exception)
            {
                throw;
            }
        }
        
        /// <summary>
        /// Get the information about the history of a path in the repository (or the root directory if no path is supplied).
        /// </summary>
        /// <param name="executionType">Type of execution.</param>        
        /// <param name="isShowIds">optional value, true to show the filesystem node revision IDs for each path in the filesystem tree.</param>
        /// <param name="isLimit">optional value, true to limit output to a maximum number of ARG items.</param>
        /// <param name="listLimits">optional value, arguments for limits.</param>
        /// <returns>Return result of execution.</returns>
        public IResult History(ExecutionType executionType, Boolean isShowIds = false, Boolean isLimit = false, String[] listLimits = null)
        {
            try
            {
                String operationType = SvnLookCommandType.history.GetDescription<DisplayAttribute>();
                String limit = SvnLookOptions.limit.GetOptionDescription<DisplayAttribute>(isLimit);
                String show_ids = SvnLookOptions.show_ids.GetOptionDescription<DisplayAttribute>(isShowIds);

                if (executionType == ExecutionType.non_used)
                {
                    Arguments = String.Format("{0} {1} {2} \"{3}\" \"{4}\"", operationType, show_ids, limit, RepositoryPath, PathInRepository);
                }
                else if (executionType == ExecutionType.revision)
                {
                    String execType = executionType.GetDescription<DisplayAttribute>();

                    if (isLimit)
                    {
                        String limts = String.Join("", listLimits);

                        Arguments = String.Format("{0} {1} {2} {3} {4} \"{5}\" \"{6}\" \"{7}\"", operationType, execType, show_ids, limit, limts, TxnRevision, RepositoryPath, PathInRepository);
                    }
                    else
                    {
                        Arguments = String.Format("{0} {1} {2} \"{3}\" \"{4}\" \"{5}\"", operationType, execType, show_ids, TxnRevision, RepositoryPath, PathInRepository);
                    }
                }

                return base.Run();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Get the author, datestamp, log message size (in bytes), and log message, followed by a newline character.
        /// </summary>
        /// <param name="executionType">Type of execution.</param>
        /// <returns>Return result of execution.</returns>
        public IResult Info(ExecutionType executionType)
        {
            try
            {
                String operationType = SvnLookCommandType.info.GetDescription<DisplayAttribute>();

                if (executionType == ExecutionType.non_used)
                {
                    Arguments = String.Format("{0} \"{1}\"", operationType, RepositoryPath);
                }
                else
                {
                    String execType = executionType.GetDescription<DisplayAttribute>();

                    Arguments = String.Format("{0} {1} \"{2}\" \"{3}\"", operationType, execType, TxnRevision, RepositoryPath);
                }

                return base.Run();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Get all information available for the lock at PATH_IN_REPOS. If PATH_IN_REPOS is not locked, print nothing.
        /// </summary>
        /// <returns>Return result of execution.</returns>
        public IResult Lock()
        {
            try
            {
                String operationType = SvnLookCommandType.locck.GetDescription<DisplayAttribute>();

                Arguments = String.Format("{0} \"{1}\" \"{2}\"", operationType, RepositoryPath, PathInRepository);

                return base.Run();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Get the log message.
        /// </summary>
        /// <param name="executionType">Type of execution.</param>
        /// <returns>Return result of execution.</returns>
        public IResult Log(ExecutionType executionType)
        {
            try
            {
                String operationType = SvnLookCommandType.log.GetDescription<DisplayAttribute>();

                if (executionType == ExecutionType.non_used)
                {
                    Arguments = String.Format("{0} \"{1}\"", operationType, RepositoryPath);
                }
                else
                {
                    String execType = executionType.GetDescription<DisplayAttribute>();

                    Arguments = String.Format("{0} {1} \"{2}\" \"{3}\"", operationType, execType, TxnRevision, RepositoryPath);
                }

                return base.Run();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Get the tree, starting at PathInRepository (if supplied; at the root of the tree otherwise), optionally showing node revision IDs.
        /// </summary>
        /// <param name="executionType">Type of execution.</param>
        /// <param name="isFullPaths">optional value, to display full paths instead of hierarchical, indented path components.</param>
        /// <param name="isNonRecursisve">optional value, to operate on a single directory only.</param>
        /// <param name="isShowIds">optional value, true to show the filesystem node revision IDs for each path in the filesystem tree.</param>
        /// <returns></returns>
        public IResult Tree(ExecutionType executionType, Boolean isFullPaths = false, Boolean isNonRecursisve = false, Boolean isShowIds = false)
        {
            try
            {
                String operationType = SvnLookCommandType.tree.GetDescription<DisplayAttribute>();
                String full_paths = SvnLookOptions.full_paths.GetOptionDescription<DisplayAttribute>(isFullPaths);
                String non_recursive = SvnLookOptions.non_recursive.GetOptionDescription<DisplayAttribute>(isNonRecursisve);
                String show_ids = SvnLookOptions.show_ids.GetOptionDescription<DisplayAttribute>(isShowIds);

                if (executionType == ExecutionType.non_used)
                {
                    Arguments = String.Format("{0} {1} {2} {3} \"{4}\" \"{5}\"", operationType, full_paths, non_recursive, show_ids, RepositoryPath, PathInRepository);
                }
                else
                {
                    String execType = executionType.GetDescription<DisplayAttribute>();

                    Arguments = String.Format("{0} {1} \"{2}\" {3} {4} {5} \"{6}\" \"{7}\"", operationType, execType, TxnRevision, full_paths, non_recursive, show_ids, RepositoryPath, PathInRepository);
                }

                return base.Run();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Get the UUID for the repository. The UUID is the repository's universal unique identifier. 
        /// The Subversion client uses this identifier to differentiate between one repository and another.
        /// </summary>
        /// <returns>Return result of execution.</returns>
        public IResult UUId()
        {
            try
            {
                String operationType = SvnLookCommandType.uuid.GetDescription<DisplayAttribute>();

                Arguments = String.Format("{0} \"{1}\"", operationType, RepositoryPath);

                return base.Run();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Get the youngest revision number of a repository.
        /// </summary>
        /// <returns>Return result of execution.</returns>
        public IResult Youngest()
        {
            try
            {
                String operationType = SvnLookCommandType.youngest.GetDescription<DisplayAttribute>();

                Arguments = String.Format("{0} \"{1}\"", operationType, RepositoryPath);

                return base.Run();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Dispose the object and resources.
        /// </summary>
        /// <param name="disposing">true to dispose and free resources.</param>
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }

        #endregion
    }    
}
